//
//  Copyright (c) Microsoft Corporation. All rights reserved.
//  Licensed under the MIT License.
//

import FluentUI
import UIKit

class CardNudgeDemoController: DemoTableViewController {

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)

        // Enable all switches by default
        CardNudgeDemoRow.allCases.forEach { row in
            self.updateSetting(for: row, isOn: true)
        }
    }

    required init?(coder: NSCoder) {
        preconditionFailure("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        readmeString = "A card nudge is a short message that helps someone discover what they can do in an app. It appears at the top of a screen, beneath the navigation bar, and pushes all other content below it.\n\nCard nudges are helpful for sending reminders and recommendations, but they don’t necessarily relate to someone’s current task. They should never be used to communicate feedback or status. To tell a user how things are going, try a notification instead."

        tableView.register(UITableViewCell.self, forCellReuseIdentifier: CardNudgeDemoController.controlReuseIdentifier)
        tableView.register(BooleanCell.self, forCellReuseIdentifier: BooleanCell.identifier)

        NotificationCenter.default.addObserver(self,
                                               selector: #selector(updateCardNudgeSize),
                                               name: UIContentSizeCategory.didChangeNotification,
                                               object: nil)

        self.configureBarButtonItems()
    }

    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        return CardNudgeDemoSection.allCases.count
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return CardNudgeDemoSection.allCases[section].rows.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let section = CardNudgeDemoSection.allCases[indexPath.section]
        let row = section.rows[indexPath.row]

        switch row {
        case .standardCard,
             .outlineCard:
            let cell = tableView.dequeueReusableCell(withIdentifier: CardNudgeDemoController.controlReuseIdentifier, for: indexPath)

            let view = cardNudges[indexPath.row]
            let contentView = cell.contentView
            contentView.addSubview(view)
            cell.selectionStyle = .none
            cell.backgroundConfiguration?.backgroundColor = .systemBackground
            view.translatesAutoresizingMaskIntoConstraints = false

            let constraints = [
                view.topAnchor.constraint(equalTo: contentView.topAnchor),
                view.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
                view.leftAnchor.constraint(equalTo: contentView.leftAnchor),
                view.rightAnchor.constraint(equalTo: contentView.rightAnchor)
            ]

            contentView.addConstraints(constraints)

            return cell

        case .mainIcon,
             .subtitle,
             .accentIcon,
             .accentText,
             .dismissButton,
             .actionButton,
             .messageAction:
            guard let cell: BooleanCell = tableView.dequeueReusableCell(withIdentifier: BooleanCell.identifier, for: indexPath) as? BooleanCell else {
                preconditionFailure("Wrong kind of cell in BooleanCell index path")
            }
            setupPropertyToggleCell(cell, for: row)
            return cell
        }
    }

    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return CardNudgeDemoSection.allCases[section].title
    }

    // MARK: - Helpers

    private func updateSetting(for row: CardNudgeDemoRow, isOn: Bool) {
        switch row {
        case .standardCard,
             .outlineCard:
            // No-op
            break
        case .mainIcon:
            cardNudges.forEach { cardNudge in
                cardNudge.state.mainIcon = (isOn ? UIImage(systemName: "gamecontroller") : nil)
            }
        case .subtitle:
            cardNudges.forEach { cardNudge in
                cardNudge.state.subtitle = (isOn ? "Subtitle" : nil)
            }
        case .accentIcon:
            cardNudges.forEach { cardNudge in
                cardNudge.state.accentIcon = (isOn ? UIImage(named: "ic_fluent_presence_blocked_10_regular", in: FluentUIFramework.resourceBundle, with: nil) : nil)
            }
        case .accentText:
            cardNudges.forEach { cardNudge in
                cardNudge.state.accentText = (isOn ? "Accent" : nil)
            }
        case .dismissButton:
            cardNudges.forEach { cardNudge in
                cardNudge.state.dismissButtonAction = (isOn ? { state in
                    let alert = UIAlertController(title: "\(state.title) was dismissed", message: nil, preferredStyle: .alert)
                    let action = UIAlertAction(title: "OK", style: .default, handler: nil)
                    alert.addAction(action)
                    self.present(alert, animated: true)
                } : nil)
            }
        case .actionButton:
            cardNudges.forEach { cardNudge in
                cardNudge.state.actionButtonTitle = (isOn ? "Action" : nil)
                cardNudge.state.actionButtonAction = (isOn ? { state in
                    let alert = UIAlertController(title: "\(state.title) action performed", message: nil, preferredStyle: .alert)
                    let action = UIAlertAction(title: "OK", style: .default, handler: nil)
                    alert.addAction(action)
                    self.present(alert, animated: true)
                } : nil)
            }
        case .messageAction:
            cardNudges.forEach { cardNudge in
                cardNudge.state.messageButtonAction = (isOn ? { state in
                    let alert = UIAlertController(title: "\(state.title) message action performed", message: nil, preferredStyle: .alert)
                    let action = UIAlertAction(title: "OK", style: .default, handler: nil)
                    alert.addAction(action)
                    self.present(alert, animated: true)
                } : nil)
            }
        }
    }

    private func setupPropertyToggleCell(_ cell: BooleanCell, for row: CardNudgeDemoRow) {
        cell.setup(title: "\(row.text)")
        cell.selectionStyle = .none
        cell.isOn = true
        cell.onValueChanged = { [weak self, row, weak cell] in
            guard let isOn = cell?.isOn, let strongSelf = self else {
                return
            }
            strongSelf.updateSetting(for: row, isOn: isOn)
            strongSelf.updateCardNudgeSize()
        }
    }

    @objc private func updateCardNudgeSize() {
        // Needs a delay because the constraints update asynchronously, but we don't
        // have a good way to know when it's done.
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
            self?.tableView?.reloadSections(IndexSet([0]), with: .none)
        }
    }

    private var cardNudges: [MSFCardNudge] = {
        var cardNudges: [MSFCardNudge] = []
        MSFCardNudgeStyle.allCases.forEach { style in
            let nudge = MSFCardNudge(style: style, title: (style == .outline ? "Outline" : "Standard"))
            cardNudges.append(nudge)
        }

        return cardNudges
    }()

    private static let controlReuseIdentifier: String = "controlReuseIdentifier"

    private enum CardNudgeDemoSection: CaseIterable {
        case cards
        case settings

        var title: String {
            switch self {
            case .cards:
                return "Cards"
            case .settings:
                return "Settings"
            }
        }

        var rows: [CardNudgeDemoRow] {
            switch self {
            case .cards:
                return [.standardCard,
                        .outlineCard]
            case .settings:
                return [.mainIcon,
                        .subtitle,
                        .accentIcon,
                        .accentText,
                        .dismissButton,
                        .actionButton,
                        .messageAction]
            }
        }
    }

    enum CardNudgeDemoRow: CaseIterable {
        case standardCard
        case outlineCard
        case mainIcon
        case subtitle
        case accentIcon
        case accentText
        case dismissButton
        case actionButton
        case messageAction

        var text: String {
            switch self {
            case .standardCard,
                 .outlineCard:
                return ""
            case .mainIcon:
                return "Main Icon"
            case .subtitle:
                return "Subtitle"
            case .accentIcon:
                return "Accent Icon"
            case .accentText:
                return "Accent"
            case .dismissButton:
                return "Dismiss Button"
            case .actionButton:
                return "Action Button"
            case .messageAction:
                return "Message Action"
            }
        }
    }
}

extension CardNudgeDemoController: DemoAppearanceDelegate {
    func themeWideOverrideDidChange(isOverrideEnabled: Bool) {
        guard let fluentTheme = self.view.window?.fluentTheme else {
            return
        }
        fluentTheme.register(tokenSetType: CardNudgeTokenSet.self,
                             tokenSet: isOverrideEnabled ? themeWideOverrideCardNudgeTokens : nil)
    }

    func perControlOverrideDidChange(isOverrideEnabled: Bool) {
        self.cardNudges.forEach { cardNudge in
            cardNudge.tokenSet.replaceAllOverrides(with: isOverrideEnabled ? perControlOverrideCardNudgeTokens : nil)
        }
    }

    func isThemeWideOverrideApplied() -> Bool {
        return self.view.window?.fluentTheme.tokens(for: CardNudgeTokenSet.self)?.isEmpty == false
    }

    // MARK: - Custom tokens

    private var themeWideOverrideCardNudgeTokens: [CardNudgeTokenSet.Tokens: ControlTokenValue] {
        return [
            .backgroundColor: .uiColor {
                UIColor(light: GlobalTokens.sharedColor(.hotPink, .tint50),
                        dark: GlobalTokens.sharedColor(.hotPink, .shade40))
            },
            .outlineWidth: .float {
                10.0
            },
            .outlineColor: .uiColor {
                UIColor(light: GlobalTokens.sharedColor(.darkRed, .tint50),
                        dark: GlobalTokens.sharedColor(.darkRed, .shade40))
            }
        ]
    }

    private var perControlOverrideCardNudgeTokens: [CardNudgeTokenSet.Tokens: ControlTokenValue] {
        return [
            .backgroundColor: .uiColor {
                UIColor(light: GlobalTokens.sharedColor(.seafoam, .tint50),
                        dark: GlobalTokens.sharedColor(.seafoam, .shade40))
            }
        ]
    }
}
